package com.lesliefang;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class KeytoolExecutor {

    /**
     * Keytool 执行结果类
     */
    public static class KeytoolResult {
        private final boolean success;
        private final String output;
        private final String errorOutput;
        private final int exitCode;

        public KeytoolResult(boolean success, String output, String errorOutput, int exitCode) {
            this.success = success;
            this.output = output;
            this.errorOutput = errorOutput;
            this.exitCode = exitCode;
        }

        public boolean isSuccess() {
            return success;
        }

        public String getOutput() {
            return output;
        }

        public String getErrorOutput() {
            return errorOutput;
        }

        public int getExitCode() {
            return exitCode;
        }

        @Override
        public String toString() {
            return "KeytoolResult{" +
                    "success=" + success +
                    ", exitCode=" + exitCode +
                    ", outputLength=" + (output != null ? output.length() : 0) +
                    ", errorLength=" + (errorOutput != null ? errorOutput.length() : 0) +
                    '}';
        }
    }

    /**
     * 执行 keytool 命令
     *
     * @param keytoolPath keytool 可执行文件路径（null 则使用系统 PATH）
     * @param arguments   keytool 参数列表
     * @param timeout     超时时间（毫秒）
     * @return 执行结果
     */
    public static KeytoolResult executeKeytool(String keytoolPath, List<String> arguments, long timeout) {
        try {
            // 构建命令
            List<String> command = new ArrayList<>();
            if (keytoolPath != null && !keytoolPath.isEmpty()) {
                command.add(keytoolPath);
            } else {
                command.add("keytool");
            }
            command.addAll(arguments);

            ProcessBuilder processBuilder = new ProcessBuilder(command);

            // 启动进程
            Process process = processBuilder.start();

            // 设置超时
            boolean finished = process.waitFor(timeout, TimeUnit.MILLISECONDS);
            if (!finished) {
                process.destroyForcibly();
                return new KeytoolResult(false, "", "keytool execution timeout", -1);
            }

            // 读取输出
            String output = readStream(process.getInputStream());
            String errorOutput = readStream(process.getErrorStream());

            int exitCode = process.exitValue();
            boolean success = (exitCode == 0);

            return new KeytoolResult(success, output, errorOutput, exitCode);

        } catch (Exception e) {
            return new KeytoolResult(false, "", e.getMessage(), -1);
        }
    }

    /**
     * 获取 keystore 列表信息
     *
     * @param keystorePath keystore 文件路径
     * @param storepass    keystore 密码
     * @param keytoolPath  keytool 路径（可选）
     * @return 执行结果
     */
    public static KeytoolResult listKeystoreEntries(String keystorePath, String storepass, String keytoolPath) {
        List<String> arguments = new ArrayList<>();
        arguments.add("-list");
        arguments.add("-keystore");
        arguments.add(keystorePath);
        arguments.add("-storepass");
        arguments.add(storepass);
        arguments.add("-v"); // 详细输出

        return executeKeytool(keytoolPath, arguments, 10000); // 10秒超时
    }

    /**
     * 获取证书指纹（MD5, SHA1, SHA256）
     *
     * @param keystorePath keystore 文件路径
     * @param alias        证书别名
     * @param storepass    keystore 密码
     * @param keytoolPath  keytool 路径（可选）
     * @return 指纹信息
     */
    public static CertificateFingerprint getCertificateFingerprint(String keystorePath, String alias,
                                                                   String storepass, String keytoolPath) {
        List<String> arguments = new ArrayList<>();
        arguments.add("-list");
        arguments.add("-keystore");
        arguments.add(keystorePath);
        arguments.add("-storepass");
        arguments.add(storepass);
        arguments.add("-alias");
        arguments.add(alias);
        arguments.add("-v");

        KeytoolResult result = executeKeytool(keytoolPath, arguments, 10000);

        if (result.isSuccess()) {
            return parseCertificateFingerprint(result.getOutput());
        } else {
            return new CertificateFingerprint(null, null, null, result.getErrorOutput());
        }
    }

    /**
     * 解析证书指纹信息
     *
     * @param output keytool 输出
     * @return 指纹对象
     */
    private static CertificateFingerprint parseCertificateFingerprint(String output) {
        String md5 = null, sha1 = null, sha256 = null;

        if (output != null) {
            // 解析 MD5 指纹
            Pattern md5Pattern = Pattern.compile("MD5:\\s*([A-F0-9:]+)");
            Matcher md5Matcher = md5Pattern.matcher(output);
            if (md5Matcher.find()) {
                md5 = md5Matcher.group(1).replace(":", "");
            }

            // 解析 SHA1 指纹
            Pattern sha1Pattern = Pattern.compile("SHA1:\\s*([A-F0-9:]+)");
            Matcher sha1Matcher = sha1Pattern.matcher(output);
            if (sha1Matcher.find()) {
                sha1 = sha1Matcher.group(1).replace(":", "");
            }

            // 解析 SHA256 指纹
            Pattern sha256Pattern = Pattern.compile("SHA256:\\s*([A-F0-9:]+)");
            Matcher sha256Matcher = sha256Pattern.matcher(output);
            if (sha256Matcher.find()) {
                sha256 = sha256Matcher.group(1).replace(":", "");
            }
        }

        return new CertificateFingerprint(md5, sha1, sha256, null);
    }

    /**
     * 证书指纹信息类
     */
    public static class CertificateFingerprint {
        private final String md5;
        private final String sha1;
        private final String sha256;
        private final String error;

        public CertificateFingerprint(String md5, String sha1, String sha256, String error) {
            this.md5 = md5;
            this.sha1 = sha1;
            this.sha256 = sha256;
            this.error = error;
        }

        public String getMd5() {
            return md5;
        }

        public String getSha1() {
            return sha1;
        }

        public String getSha256() {
            return sha256;
        }

        public String getError() {
            return error;
        }

        public boolean hasError() {
            return error != null && !error.isEmpty();
        }

        @Override
        public String toString() {
            if (hasError()) {
                return "Error: " + error;
            }
            return "CertificateFingerprint{" +
                    "md5='" + md5 + '\'' +
                    ", sha1='" + sha1 + '\'' +
                    ", sha256='" + sha256 + '\'' +
                    '}';
        }
    }

    /**
     * 获取 keystore 信息
     *
     * @param keystorePath keystore 文件路径
     * @param storepass    keystore 密码
     * @param keytoolPath  keytool 路径（可选）
     * @return keystore 信息
     */
    public static KeystoreInfo getKeystoreInfo(String keystorePath, String storepass, String keytoolPath) {
        KeytoolResult result = listKeystoreEntries(keystorePath, storepass, keytoolPath);

        if (result.isSuccess()) {
            return parseKeystoreInfo(result.getOutput());
        } else {
            return new KeystoreInfo(null, null, result.getErrorOutput());
        }
    }

    /**
     * 解析 keystore 信息
     */
    private static KeystoreInfo parseKeystoreInfo(String output) {
        List<String> aliases = new ArrayList<>();
        String keystoreType = null;

        if (output != null) {
            // 解析 keystore 类型
            Pattern typePattern = Pattern.compile("Keystore type: (.+)");
            Matcher typeMatcher = typePattern.matcher(output);
            if (typeMatcher.find()) {
                keystoreType = typeMatcher.group(1);
            }

            // 解析所有别名
            Pattern aliasPattern = Pattern.compile("Alias name: (.+)");
            Matcher aliasMatcher = aliasPattern.matcher(output);
            while (aliasMatcher.find()) {
                aliases.add(aliasMatcher.group(1));
            }
        }

        return new KeystoreInfo(keystoreType, aliases, null);
    }

    /**
     * Keystore 信息类
     */
    public static class KeystoreInfo {
        private final String type;
        private final List<String> aliases;
        private final String error;

        public KeystoreInfo(String type, List<String> aliases, String error) {
            this.type = type;
            this.aliases = aliases != null ? aliases : new ArrayList<>();
            this.error = error;
        }

        public String getType() {
            return type;
        }

        public List<String> getAliases() {
            return aliases;
        }

        public String getError() {
            return error;
        }

        public boolean hasError() {
            return error != null && !error.isEmpty();
        }

        @Override
        public String toString() {
            if (hasError()) {
                return "Error: " + error;
            }
            return "KeystoreInfo{" +
                    "type='" + type + '\'' +
                    ", aliases=" + aliases +
                    '}';
        }
    }

    /**
     * 读取输入流内容
     */
    private static String readStream(java.io.InputStream inputStream) throws IOException {
        StringBuilder result = new StringBuilder();
        try (BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
            String line;
            while ((line = reader.readLine()) != null) {
                result.append(line).append("\n");
            }
        }
        return result.toString();
    }

    /**
     * 查找系统中的 keytool 路径
     */
    public static String findKeytoolPath() {
        String javaHome = System.getProperty("java.home");
        if (javaHome != null) {
            File keytool = new File(javaHome, "bin/keytool");
            if (keytool.exists()) {
                return keytool.getAbsolutePath();
            }
            // Windows 系统
            keytool = new File(javaHome, "bin/keytool.exe");
            if (keytool.exists()) {
                return keytool.getAbsolutePath();
            }
        }
        return "keytool"; // 使用系统 PATH 中的 keytool
    }

    // 使用示例
    public static void main(String[] args) {
        // 示例：获取 keystore 信息
        String keystorePath = "path/to/your/keystore.jks";
        String storepass = "your_store_password";
        String alias = "your_alias";

        System.out.println("=== 查找 keytool 路径 ===");
        String keytoolPath = findKeytoolPath();
        System.out.println("Keytool path: " + keytoolPath);

        // 检查 keystore 文件是否存在
        File keystoreFile = new File(keystorePath);
        if (!keystoreFile.exists()) {
            System.out.println("Keystore file not found: " + keystorePath);
            return;
        }

        System.out.println("\n=== 获取 Keystore 信息 ===");
        KeystoreInfo info = getKeystoreInfo(keystorePath, storepass, keytoolPath);
        System.out.println(info);

        if (!info.hasError() && !info.getAliases().isEmpty()) {
            System.out.println("\n=== 获取证书指纹 ===");
            String firstAlias = info.getAliases().get(0);
            CertificateFingerprint fingerprint = getCertificateFingerprint(
                    keystorePath, firstAlias, storepass, keytoolPath);
            System.out.println(fingerprint);

            if (!fingerprint.hasError()) {
                System.out.println("MD5: " + fingerprint.getMd5());
                System.out.println("SHA1: " + fingerprint.getSha1());
                System.out.println("SHA256: " + fingerprint.getSha256());
            }
        }

        // 直接执行自定义 keytool 命令
        System.out.println("\n=== 执行自定义命令 ===");
        List<String> customArgs = List.of("-help");
        KeytoolResult helpResult = executeKeytool(keytoolPath, customArgs, 5000);
        if (helpResult.isSuccess()) {
            System.out.println("Help output length: " + helpResult.getOutput().length());
        } else {
            System.out.println("Help command failed: " + helpResult.getErrorOutput());
        }
    }
}
